#define GL_GLEXT_PROTOTYPES
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>
#include <GL/glext.h>

#include <string>
#include <stdexcept>
#include <iostream>

//эта функция банально кидает исключение на ошибке
void glCheckError()
{
	GLenum err=glGetError();
	if(err)throw std::runtime_error(std::string("opengl error: ")+
		(const char*)gluErrorString(err));	
}
//эта функция банально создает 1 шадер
static GLuint create_shader(GLenum type, const char* shader_source)
{
	GLuint shader = glCreateShader(type);
	if(!shader)throw std::runtime_error("cannot create shader");
	try{
		glShaderSourceARB(shader, 1, &shader_source, NULL);
		glCompileShaderARB(shader);
		GLint result;
		glGetShaderiv(shader, GL_COMPILE_STATUS, &result);
		if (result!=GL_TRUE)
		{
			GLint errorLogLength;
			glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &errorLogLength);
			//Create a buffer to read compilation error message
			char errorLog[errorLogLength+1];
			//Used to get the final length of the log.
			glGetShaderInfoLog(shader, errorLogLength, &errorLogLength, errorLog);
			errorLog[errorLogLength]=0;
			throw std::runtime_error(std::string("opengl error: ")+errorLog);
		}	
	}catch(...){
		glDeleteShader(shader);
		throw;
	}
	return shader;
}
GLuint load_shaders(const char * vertex, const char * fragment)
{
	// Create Shader And Program Objects
	GLuint my_program=glCreateProgram();
	if(!my_program)throw std::runtime_error("cannot create program");
	try{
		try{
			glAttachShader(my_program, create_shader(GL_VERTEX_SHADER,vertex));
		}catch(std::exception& ex){
			std::cerr<<"Vertex shader: "<<std::endl
					 <<ex.what()<<std::endl;
			throw std::runtime_error("failed to load program");
		}
		try{
			glAttachShader(my_program, create_shader(GL_FRAGMENT_SHADER,fragment));
		}catch(std::exception& ex){
			std::cerr<<"Fragment shader: "<<std::endl
					 <<ex.what()<<std::endl;
			throw std::runtime_error("failed to load program");
		}
		glLinkProgram(my_program);
		//проверим не было ли ошибки!
		GLint result;
		glGetProgramiv(my_program, GL_LINK_STATUS, &result);
		if (result!=GL_TRUE)
		{
			GLint errorLogLength;
			glGetProgramiv(my_program, GL_INFO_LOG_LENGTH, &errorLogLength);
			//Create a buffer to read compilation error message
			char errorLog[errorLogLength+1];
			//Used to get the final length of the log.
			glGetProgramInfoLog(my_program, errorLogLength, &errorLogLength, errorLog);
			errorLog[errorLogLength]=0;
			throw std::runtime_error(std::string("opengl error: ")+errorLog);
		}	
	}catch(...){
		glDeleteProgram(my_program);
		throw;
	}
	return my_program;
}
